package com.sf.dlb.utils;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.Key;
import java.security.Security;

/**
 * 根据公司的网站修改成追加的包名
 * 
 * 参考http://my.oschina.net/nicsun/blog/95632
 * 
 * @author yxtwang
 *
 */
public class AES256EncryptionUtils {

	// 日志文件打印
	private static Log logger = LogFactory.getLog(AES256EncryptionUtils.class);
	/**
	 * 密钥算法 java6支持56位密钥，bouncycastle支持64位
	 */
	private static final String KEY_ALGORITHM = "AES";

	/**
	 * 加密/解密算法/工作模式/填充方式
	 * 
	 * JAVA6 支持PKCS5PADDING填充方式 Bouncy castle支持PKCS7Padding填充方式
	 */
	private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS7Padding";

	// 实例
	private static AES256EncryptionUtils aesutils = null;

	private static final String ENCODE_UTF_8 = "UTF-8";

	/**
	 * 固定的key 256位
	 */
	private static final String secretKey = "shufenrd@dlb.com";

	/**
	 * 构造函数
	 */
	private AES256EncryptionUtils() {
	}

	/**
	 * aes的实例
	 * 
	 * @return
	 */
	public static synchronized AES256EncryptionUtils getInstance() {
		if (aesutils == null) {
			aesutils = new AES256EncryptionUtils();
		}
		return aesutils;
	}

	/**
	 * 生成密钥，java6只支持56位密钥，bouncycastle支持64位密钥
	 * 
	 * @return byte[] 二进制密钥
	 */
	private byte[] initkey() {
//      //实例化密钥生成器  
      Security.addProvider(new BouncyCastleProvider());
//      KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM, "BC");  
//      //初始化密钥生成器，AES要求密钥长度为128位、192位、256位  
//      kg.init(256);  
//      kg.init(128);
//      //生成密钥  
//      SecretKey secretKey=kg.generateKey();
//      //获取二进制密钥编码形式  
//      return secretKey.getEncoded();  
		// 为了便于测试，这里我把key写死了，如果大家需要自动生成，可用上面注释掉的代码
		byte[] test = secretKey.getBytes();
		return test;
	}
	/**将16进制转换为二进制
	 * @param hexStr
	 * @return
	 */
	public static byte[] parseHexStr2Byte(String hexStr) {
		if (hexStr.length() < 1)
			return null;
		byte[] result = new byte[hexStr.length()/2];
		for (int i = 0;i< hexStr.length()/2; i++) {
			int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
			int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
			result[i] = (byte) (high * 16 + low);
		}
		return result;
	}

	/**
	 * 转换密钥
	 * 
	 * @param key
	 *            二进制密钥
	 * @return Key 密钥
	 */
	private Key toKey(byte[] key) throws Exception {
		// 实例化DES密钥
		// 生成密钥
		SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM);
		return secretKey;
	}

	/**
	 * 文件的生成和解密
	 * 
	 * @param srcFilePath
	 *            源文件路径
	 * @param destFilePath
	 *            加密后的文件的路径
	 * @return
	 */
	public boolean fileDecrypt(String srcFilePath, String destFilePath) {
		// 默认失败
		boolean isSucess = false;
		// 原文件读取
		File srcRead = new File(srcFilePath);
		// 写入文件
		File destFile = new File(destFilePath);

		if (!srcRead.exists()) {
			logger.error("文件不存在！");
			return isSucess;
		}

		if (!destFile.exists()) {
			logger.info("创建文件！");
			try {
				destFile.createNewFile();
			} catch (IOException e) {
				logger.error("创建文件失败！");
				e.printStackTrace();
				return isSucess;
			}
		}
		// 图片不能大于512K
		readWriteGraDecrypt(srcRead, destFile);
		isSucess = true;
		return isSucess;
	}

	/**
	 * 文件的解密
	 * 
	 * @param sourceFile
	 *            源文件的文件信息
	 * @param destFile
	 *            目的文件的信息
	 */
	private void readWriteGraDecrypt(File sourceFile, File destFile) {
		FileInputStream in = null;
		FileOutputStream out = null;
		try {
			in = new FileInputStream(sourceFile);
			out = new FileOutputStream(destFile);
			byte[] fileContent = new byte[(int) sourceFile.length()];
			in.read(fileContent);
			byte[] decrypt = null;
			decrypt = decrypt(fileContent);
			out.write(decrypt);
			out.close();
			in.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 文件的生成和加密
	 * 
	 * @param srcFilePath
	 *            源文件路径
	 * @param destFilePath
	 *            加密后的文件的路径
	 * @return
	 */
	public boolean fileEncrypt(String srcFilePath, String destFilePath) {
		// 默认失败
		boolean isSucess = false;
		// 原文件读取
		File srcRead = new File(srcFilePath);
		// 写入文件
		File destFile = new File(destFilePath);

		if (!srcRead.exists()) {
			logger.error("文件不存在！");
			return isSucess;
		}

		if (!destFile.exists()) {
			if (!FileUtils.createFile(destFilePath)) {
				logger.info("创建文件！");
			} else {
				logger.error("创建文件失败！");
				return isSucess;
			}
		}
		// 图片不能大于512K
		this.readWriteGraEncrypt(srcRead, destFile);
		isSucess = true;
		return isSucess;
	}

	/**
	 * 加密
	 * 
	 * @param sourceFile
	 *            源文件的文件信息
	 * @param destFile
	 *            目的文件的信息
	 */
	private void readWriteGraEncrypt(File sourceFile, File destFile) {
		FileInputStream in = null;
		FileOutputStream out = null;

		try {
			in = new FileInputStream(sourceFile);
			out = new FileOutputStream(destFile);
			byte[] fileContent = new byte[(int) sourceFile.length()];
			in.read(fileContent);
			byte[] enbyte = null;
			enbyte = encrypt(fileContent);
			out.write(enbyte);
			in.close();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 数据加密
	 * 
	 * @param data 待加密数据
	 * @return byte[] 加密后的数据
	 */
	public byte[] encrypt(byte[] data) throws Exception {
		byte[] key = this.initkey();
		// 还原密钥
		Key k = this.toKey(key);
		/**
		 * 实例化 使用 PKCS7PADDING 填充方式，按如下方式实现,就是调用bouncycastle组件实现
		 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
		 */
		Security.addProvider(new BouncyCastleProvider());
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		// 初始化，设置为加密模式
		cipher.init(Cipher.ENCRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 数据加密
	 * 
	 * @param data
	 *            待加密数据
	 * @param key
	 *            密钥
	 * @return byte[] 加密后的数据
	 */
	public byte[] encrypt(byte[] data, byte[] key) throws Exception {
		// 还原密钥
		Key k = this.toKey(key);
		/**
		 * 实例化 使用 PKCS7PADDING 填充方式，按如下方式实现,就是调用bouncycastle组件实现
		 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
		 */
		Security.addProvider(new BouncyCastleProvider());
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		// 初始化，设置为加密模式
		cipher.init(Cipher.ENCRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 数据加密
	 * 
	 * @param str 待加密数据
	 * @return byte[] 加密后的数据
	 */
	public String encrypt(String str) {
		String base64retStr = "";
		try {
			byte[] key = this.initkey();
			byte[] data = str.getBytes(ENCODE_UTF_8);
			// 还原密钥
			Key k = this.toKey(key);
			/**
			 * 实例化 使用 PKCS7PADDING 填充方式，按如下方式实现,就是调用bouncycastle组件实现
			 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
			 */
			Security.addProvider(new BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
			// 初始化，设置为加密模式
			cipher.init(Cipher.ENCRYPT_MODE, k);
			// 执行操作
			// base64的解码
			byte[] buf = cipher.doFinal(data);
			// 转化成Base64编码
			base64retStr = Base64.encodeBase64String(buf);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}

		return base64retStr;
	}
	/**
	 * 解密数据
	 * 
	 * @param data
	 *            待解密数据
	 * @return byte[] 解密后的数据
	 */
	public byte[] decrypt(byte[] data) throws Exception {

		// 解密Key
		byte[] key = this.initkey();

		// 欢迎密钥
		Key k = this.toKey(key);
		/**
		 * 实例化 使用 PKCS7PADDING 填充方式，按如下方式实现,就是调用bouncycastle组件实现
		 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
		 */
		Security.addProvider(new BouncyCastleProvider());
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		// 初始化，设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 数据解密
	 * 
	 * @param data
	 *            待解密数据
	 * @param key
	 *            密钥
	 * @return byte[] 解密后的数据
	 */
	public byte[] decrypt(byte[] data, byte[] key) throws Exception {
		// 欢迎密钥
		Key k = this.toKey(key);
		/**
		 * 实例化 使用 PKCS7PADDING 填充方式，按如下方式实现,就是调用bouncycastle组件实现
		 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
		 */
		Security.addProvider(new BouncyCastleProvider());
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化，设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 数据解密
	 * 
	 * @param str 待解密数据
	 * @return byte[] 解密后的数据
	 */
	public String decrypt(String str) {
		byte[] key = this.initkey();
		// 解密数据
		byte[] base64;
		String retStr = "";
		try {
			// 欢迎密钥
			Key k = this.toKey(key);

			base64 = Base64.decodeBase64(str);

			/**
			 * 实例化 使用 PKCS7PADDING 填充方式，按如下方式实现,就是调用bouncycastle组件实现
			 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
			 */
			Security.addProvider(new BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
			// 初始化，设置为解密模式
			cipher.init(Cipher.DECRYPT_MODE, k);
			// 执行操作
			// base64的解码
			byte[] buf = cipher.doFinal(base64);
			// 转化为字符串
			retStr = new String(buf, ENCODE_UTF_8);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return retStr;
	}

	public static void main(String[] args) {
//		String idcard = "18021072603";
//		String encode = AES256EncryptionUtils.getInstance().encrypt(idcard);
//		System.out.println("原串：" + idcard);
//		System.out.println("加密后的串：" + encode);
//		System.out.println("解密后的串：" + AES256EncryptionUtils.getInstance().decrypt(encode));
		String str="{\n" +
				"    \"newId\": \"51\"\n" +
				"}";
		System.out.println("加密后的串：" + AES256EncryptionUtils.getInstance().encrypt(str));

	}
}